/**
 * RayleighDistribution : Definition de la loi de Rayleigh
 *
 * @author maria ladoue
 * @version 0.1, 30/08/02 
 */
package br.unb.statistic.distribution;

import java.util.HashMap;
import br.unb.statistic.InterPacketTimeGenerator;
import br.unb.statistic.RandomGenerator;
import br.unb.statistic.inference.Inference;
import br.unb.utils.Resource;

public class RayleighDistribution extends GenericContinuousDistribution implements RandomGenerator, InterPacketTimeGenerator {

    /**
     * Equation de la densite:<BR>
     *  f(x)= x/alpha^2*exp(-x^2/(2*alpha^2))<BR>
     */
    private static int ALPHA = 0;

    // Definition des constructeurs
    public RayleighDistribution() {
        paramsCount = 1;
        name = new String("Rayleigh");

        params = new double[paramsCount]; // initialisation du tableau des valeurs des parametres
        paramNames = new String[paramsCount]; // initialisation du tableau des noms des parametres
        params[ALPHA] = 0.1d;
        paramNames[ALPHA] = new String("alpha");
    }

    public RayleighDistribution(double unAlpha) throws IllegalArgumentException {
        this();
        if (unAlpha > 0) {
            setParam(ALPHA, unAlpha);
        } else {
            throw new IllegalArgumentException(Resource.getString("RAYLEIGHDISTRIBUTION.CONSTRUCTOR_ALPHA_MUST_BE_GREATER_THAN_0"));
        }
    }

    public RayleighDistribution(double[] params) throws IllegalArgumentException {
        this();
        if (hasValidParam(params)) {
            setParams(params);
        } else {
            throw new IllegalArgumentException(Resource.getString("RAYLEIGHDISTRIBUTION.CONSTRUCTOR_ALPHA_MUST_BE_GREATER_THAN_0"));
        }
    }

    public boolean hasValidParam(double[] desParams) {
        if (desParams[ALPHA] > 0) {
            return true;
        } else {
            return false;
        }
    }

    // Definitions de quelques methodes
    /**
     * Returns the value of the probability distribution function at x
     */
    public double pdf(double x) {
        if (x >= 0) {
            return (x / Math.pow(params[ALPHA], 2d)
                    * Math.exp(-Math.pow(x, 2d)) / (2 * Math.pow(params[ALPHA], 2d)));
        } else {
            return 0;
        }
    }

    /**
     * Returns the value of the cumulative distribution function at x (= Fonction de repartition)
     */
    public double cdf(double x) {
        if (x > 0) {
            return (1.0d - Math.exp(-1d * Math.pow(x, 2d) / (2 * Math.pow(params[ALPHA], 2d))));
        } else {
            return 0;
        }
    }

    /**
     * Return the value of Inverse Function at x
     * @param x with x>=0 and x<=1
     */
    public double inverseCdf(double x) throws IllegalArgumentException {
        if (x >= 0 && x <= 1) {
            return Math.sqrt(-2d * Math.pow(params[ALPHA], 2) * Math.log(1 - x));
        } else {
            throw new IllegalArgumentException(Resource.getString("RAYLEIGHDISTRIBUTION.INVERSECDF_X_MUST_BE_>_0_AND_<_1"));
        }
    }

    public double mean() {
        return (params[ALPHA] * Math.sqrt(Math.PI / 2));
    }

    public double var() {
        return (4 - Math.PI) * Math.pow(params[ALPHA], 2d) / 2;
    }

    public double rand() {
        return this.inverseCdf(RandomGenerator.random.nextDouble());
    }

    public double nextInterPacketTime() {
        return rand();
    }

    public String getEquation() {
        return new String(" f(x)= x/alpha^2*exp(-x^2/(2*alpha^2))");
    }

    public void setParameters(HashMap parameters) {
        double mean;
        if (parameters.get("mean") != null) {
            mean = Double.parseDouble((String) parameters.get("mean"));
        } else {
            mean = 1.0d / Double.parseDouble((String) parameters.get("rate"));
        }
        if (mean > 0) {
            setParam(ALPHA, mean / Math.sqrt(Math.PI / 2));
        }
    }

    public void estimateParameters(Inference inf) {
        double alfa = Math.sqrt(inf.getMeanSquare() / 2);
        setParam(ALPHA, alfa);
    }
    /* //Old code with the testing unit and stuff YO!!!
    public static void main(String args[]){
    RayleighDistribution dist = new RayleighDistribution(5.9);
    RayleighDistribution dist2 = new RayleighDistribution();
    Log log = new Log("teste",false);
    for(int i=0; i<3000; i++){
    log.write(""+dist.rand());
    }
    log.close();
    try {
    DataReader dr = new DataReader(log.getFile());
    Inference inf = new Inference(dr,0);
    dist2.calculateMLE(inf);
    System.out.println(dist2.getParam(0));
    } catch (IOException e) {
    e.printStackTrace();
    }
    }*/
}
